package zhttp_client

import (
	"crypto/tls"
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"
)

const (
	Post                = "POST"                              //
	Get                 = "GET"                               //
	Options             = "OPTIONS"                           //
	Put                 = "PUT"                               //
	ContentCategoryName = "Content-CategoryName"              //
	ApplicationForm     = "application/x-www-form-urlencoded" //
)

// "Content-CategoryName", "application/x-www-form-urlencoded"

type ResponseInfo struct {
	Resp       *http.Response
	Head       http.Header
	Cookies    []*http.Cookie
	Body       string
	BufferBody []byte
	Status     int
}

// GoGet Get提交
func GoGet(strUrl string, headData http.Header) (response ResponseInfo, err error) {
	response, err = submit(Get, strUrl, "", headData)
	return
}

// SecureBody 双向认证提交
func SecureBody(strUrl, bodyData string, headData http.Header, certFile, keyFile string) (response ResponseInfo, err error) {
	var tr *http.Transport
	if tr, err = loadCert(certFile, keyFile); err == nil {
		client := &http.Client{
			Transport: tr,
		}
		response, err = submitSecure(client, Post, strUrl, bodyData, headData)
	}
	return
}

// Body Post提交
func Body(strUrl, bodyData string, headData http.Header) (response ResponseInfo, err error) {
	response, err = submit(Post, strUrl, bodyData, headData)
	return
}

// Form Form提交
func Form(strUrl string, formData map[string]string, headData http.Header) (response ResponseInfo, err error) {
	data := joinForm(formData)
	headData.Set(ContentCategoryName, ApplicationForm)
	response, err = submit(Post, strUrl, data, headData)
	return
}

// SecureForm 双向认证提交
func SecureForm(strUrl string, formData map[string]string, headData http.Header, certFile, keyFile string) (response ResponseInfo, err error) {
	var tr *http.Transport
	if tr, err = loadCert(certFile, keyFile); err == nil {
		client := &http.Client{
			Transport: tr,
		}
		data := joinForm(formData)
		headData.Set(ContentCategoryName, ApplicationForm)
		response, err = submitSecure(client, Post, strUrl, data, headData)
	}

	return
}

// 连接Form参数
func joinForm(formData map[string]string) (formStr string) {
	for n, v := range formData {
		formStr += fmt.Sprintf("%s=%s&", n, v)
	}
	if formStr != "" {
		formStr = formStr[0 : len(formStr)-1]
	}
	return
}

// 加载CA证书
func loadCert(certFile, keyFile string) (tr *http.Transport, err error) {
	var cert tls.Certificate
	if cert, err = tls.LoadX509KeyPair(certFile, keyFile); err == nil {
		tr = &http.Transport{
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: true,
				Certificates:       []tls.Certificate{cert},
			},
		}
	}
	return
}

func submitSecure(client *http.Client, method, strUrl, bodyData string, headData http.Header) (response ResponseInfo, err error) {
	var req *http.Request
	if req, err = http.NewRequest(method, strUrl, strings.NewReader(bodyData)); err != nil {
		return
	}
	defer func() {
		_ = req.Body.Close()
	}()
	if headData != nil {
		for n, v := range headData {
			for j := 0; j < len(v); j++ {
				req.Header[n] = []string{v[j]}
			}
		}
	}
	var resp *http.Response
	if resp, err = client.Do(req); err == nil {
		defer func() {
			err = resp.Body.Close()
		}()
		response.Status = resp.StatusCode
		response.Head = resp.Header
		response.Cookies = resp.Cookies()
		response.Resp = resp
		if response.BufferBody, err = io.ReadAll(resp.Body); err != nil {
			return
		}
		response.Body = string(response.BufferBody)
	}
	return
}

func submit(method, strUrl, bodyData string, headData http.Header) (response ResponseInfo, err error) {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{
		Transport: tr,
		Timeout:   time.Second * 5,
	}
	response, err = submitSecure(client, method, strUrl, bodyData, headData)
	return
}
